home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS Toolkit
/
BBS Toolkit.iso
/
rbbs_pc
/
msgtos20.zip
/
SPAZ_150.LZH
/
SPAZ.ASM
next >
Wrap
Assembly Source File
|
1990-10-07
|
67KB
|
2,044 lines
;---------------------------------------------------------------------;
; ;
; SPAZ 1.50 ;
; October 7, 1990 ;
; ;
; By Dan Thomson, Andrew Farmer and Jeffrey Nonken. ;
; ;
; ;
; SOURCE CODE ;
; ;
; ;
; Copyright (c) 1989-1990 Dan Thomson and Andrew Farmer. ;
; All Rights Reserved. ;
; ;
;---------------------------------------------------------------------;
name SPAZ
page 60,132
title Smart Pak, Arc and Zoo Shell
false equ 00h
tab equ 09h ;ASCII tab
lf equ 0ah ;ASCII line feed
cr equ 0dh ;ASCII carriage return
blank equ 20h ;ASCII blank
arc_len equ 21h ;Only save info for sort
DOS equ 21h ;DOS int call
CntrolC equ 23h ;Control C checking...
cmdtail equ 80h ;Offset to command tail
true equ 255
bsize equ 4096 ;Size of copy buffer
; If you have lots of memory, (Not running a multi-tasker) then the
; following variables can be changed to allow running SPAZ a little
; faster, but using alot more memory....
; 1. Entries is the number of members in a standard ARC file that
; can be stored for sorting. If an ARC has more than 150, the
; file is not sorted. This can be increased until buffers reach
; (64K - code size). Each entry needs 29 bytes of buffer space.
Entries equ 150
; 2. This entry controls how many file names will be stored in
; memory. This is used during wild card processing to run
; SPAZ on each individual name. It has been set at 30 to
; allow most systems to run without writing to disk. If you
; run a busy mail system or process alot of archives, this
; can be increased (at the cost of memory) for faster processing.
NamesFound equ 30
;DOS interupt equates...
CharacterOutput equ 02h
OutputString equ 09h
SetDTA equ 1ah
SetVector equ 25h
GetVector equ 35h
CreateFile equ 3ch
OpenFile equ 3dh
CloseFile equ 3eh
ReadFile equ 3fh
WriteFile equ 40h
DeleteFile equ 41h
MoveFilePointer equ 42h
GetOrSetAttribute equ 43h
ModifyMemory equ 4ah
ExecuteProgram equ 4bh
ExitWithCode equ 4ch
GetReturnCode equ 4dh
SearchForFirst equ 4eh
SearchForNext equ 4fh
RenameFile equ 56h
cseg segment para public 'code'
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
org 100h ;Skip to end of the PSP
entry: jmp start ;comm file entry always 0100H
TitleScreen db cr,lf,'SPAZ 1.50; Written by Dan Thomson, Andrew Farmer and Jeffrey Nonken.',cr,lf
db 'Copyright (c) 1989-1990 Dan Thomson & Andrew Farmer. All Rights Reserved.',cr,lf
TitleLength equ $-TitleScreen
Usage db cr,lf,'Syntax/Usage: SPAZ [switches] Path\Archive [switches] [files....]'
db cr,lf,'Square brackets indicate optionals. Switches are set with - or /.'
db cr,lf,cr,lf,'Switches:',cr,lf,cr,lf
db ' -A Will use ONLY "ARCE" on standard (ARC Style) archives.',cr,lf
db ' -D Will delete the archive if the extract was successful.',cr,lf
db ' -F Will process all Compressed Mail bundles found in Dir.',cr,lf
db ' -Maddr Will calculate Compressed Mail bundle name to show the',cr,lf
db ' sending Net Address. "addr" is YOUR Net/Node address.',cr,lf
db ' -N Will NOT attempt to sort the archive prior to extract.',cr,lf
db ' -O|-R Overwrite. Will NOT prompt if existing file is found.',cr,lf
db ' -V Verbose Mode. Will display the runtime configuration.',cr,lf,cr,lf
db 'If -F is used then "Archive" MUST be a Path ONLY, not a Filename.',cr,lf
db 'Use of -F forces -D and -O to be set TRUE and -N to be set False.',cr,lf
UsageLength equ $-Usage
even
errmsg dw err2,err2,err2,err4,err5,err13
dw err13,err8,err8,err10,err11,err5
dw err13,err15,err15,err2,err2,err2
dw err20,err20,err21,err22,err23,err24,err25
err2 db cr,lf,'File not found: ',0
err4 db cr,lf,'Too many open files.',cr,lf,0
err5 db cr,lf,'Access denied.',cr,lf,0
err8 db cr,lf,'Insufficient memory.',cr,lf,0
err10 db cr,lf,'Invalid environment.',cr,lf,0
err11 db cr,lf,'Invalid format.',cr,lf,0
err13 db cr,lf,'Invalid data.',cr,lf,0
err15 db cr,lf,'Invalid drive was specified.',cr,lf,0
err20 db cr,lf,'Invalid file format, not changed.',cr,lf,0
err21 db cr,lf,'Too many archive entries.',cr,lf,0
err22 db cr,lf,'Unarchiver not found on path.',cr,lf,0
err23 db cr,lf,'Invalid Command Line Option used.',cr,lf,0
err24 db cr,lf,'Archive name not specified!',cr,lf,0
err25 db cr,lf,'Invalid directory specified.',cr,lf,'$'
NoMail db cr,lf,'No Compressed Mail Bundles Found in Directory!',cr,lf,cr,lf,'$'
SortErr db 'Sort failed, attempting extract anyway...',cr,lf,0
zerr db 'Problem reading archive for type check.',cr,lf,0
crlf equ $-3
TempErr db 'Unable to process temporary file, aborting.',cr,lf,'$'
del_msg db cr,lf,'Extract successful - Unlinking ',0
will db cr,lf,'Will ',0
wont db cr,lf,'Will NOT ',0
info1 db 'use ARCE on standard (ARC style) archives.',0
info2 db 'delete the archives if extract was successful.',0
info3 db 'attempt to sort the archives.',cr,lf,0
info4 db ' - From: ',0
info5 db 'expand network addresses.',0
info6 db 'process Compressed Mail bundles ONLY.',0
info7 db 'operate in overwrite mode.',0
msg1 db ' Adjusting: ',0
msg2 db '- Location = ',0
msg3 db ' Length = ',0
msg4 db 'Searching: ',0
UnArc1 db 'PKXARC.EXE',0
UnArc2 db 'PKXARC.COM',0
UnArc3 db 'PKUNPAK.EXE',0
UnArc4 db 'LOOZ.EXE',0
UnArc5 db 'PAK.EXE',0
UnArc6 db 'ARCE.COM',0
UnArc7 db 'ZOO.EXE',0
UnArc8 db 'DWC.EXE',0
UnArc9 db 'PKUNZIP.EXE',0
UnArc10 db 'LHARC.EXE',0
on_disk db 0 ;True if names on disk .jjn
num_names db 0 ;# of filenames in buffer .jjn
num_hdr db 0 ;Number of headers input
first db true ;Flag for search first/next
flag db false ;Show sort done on pass
Zooflag db false ;Flag to signify zoo file
Crushed db false ;Flag to signify crushed files
A_Flag db false ;Set no default archiver
D_Flag db false ;Set no delete when finished
F_Flag db false ;Set no mail only stuff
M_Flag db false ;Show net/node on extract?
N_Flag db true ;Set default sort performed
O_Flag db false ;Set default to non-overwrite
Q_Flag db true ;Set default to quiet
IsZip db false ;Flag to show ZIP file
IsDWC db false ;Flag to show DWC file
IsLZH db false ;Flag to show LZH file
Parsed db false ;Flag to show names were parsed
Got_name db false ;Cmd line fname is OK...
Characters db false ;Print string char counter
Last_Chance db false ;Flag for Arce useage
elevel db 0 ;Last reported error level
count db 0 ;Number of passes complete
order db 0 ;Flag to show archive in order
temp db 'SpazTmp1.$$$',0 ;Temp filename to use
thomlen equ $-temp ; .jjn
filename_file db 'SpazTmp2.$$$',0 ;Filename for list of files
end_arc db 1Ah,0 ;Mark to show end of arc
even
arg_len dw 0 ;Length of command line arg
buf_pos dw 0 ;Position in header buffer
endpath dw 0 ;Holds end of path address
pathlen dw 0 ;Holds length of path .jjn
files_handle dw 0 ;Handle for filespec file .jjn
name_count dw 0 ;Number of filenames found .jjn
names_used dw 0 ;Number of names used after.jjn
; all the names were found .jjn
fname_ptr dw 0 ;Point into filename buffer.jjn
Opt_Address dw false ;Pointer to cmd line fname
Opt_Length dw false ;Address of cmd line fname
high_pos dw 0 ;High byte of file pointer
low_pos dw 0 ;Low byte of file pointer
in_handle dw 0 ;Handle for read file
out_handle dw 0 ;Handle for write file
par_blk dw 0 ;Copy of parent's environment
dw offset cmd_cnt ;Pointer to command line
sg1 dw 0
dw offset fcb1
sg2 dw 0
dw offset fcb2
sg3 dw 0
stk_seg dw 0 ;Saved stack segment
stk_ptr dw 0 ;Saved stack pointer
dir dw 0 ;Pointer for PATH search
enddir dw 0 ;End address of PATH variable
cmd1_cnt dw 0 ;Length of wildcard filename
env_len dw 0 ;Length of PATH in Environment
BundlePosition dw offset BundleNames ;Current position for mail
env db 'PATH',0 ;Environment variable to find
DefaultBundle db '*.MO?',0 ;First mail type to look for
BundleNames db 'TUWETHFRSASU' ; and the rest of 'em....
Spaz proc near ;Entry point from MS-DOS
start: mov AX,CS
mov sg1,AX
mov sg2,AX
mov sg3,AX
mov AH,SetDTA ;AH = Set Disk Tranfer Area
mov DX,offset dta_buf ;Address of scratch space
int DOS ;Give it to DOS
xor AX,AX
mov word ptr Names_Count,AX
cli ;Disable interupts
lea sp,bottom-1 ;Move stack to save position
sti ;OK for interups now...
mov DX,offset bottom ;Point DX to end of Spaz
mov BX,DX ;Info needed in BX
add BX,0fh ;Add 1 paragraph to it
mov CL,4 ;CL = counter for shift
shr BX,CL ;= BX/16 (# of paras needed)
mov AH,ModifyMemory ;AH = Modify memory block
int DOS ;Extra memory released...
; First, identify self and examine parameters...
mov DX,offset TitleScreen ;DX points to message
mov BX,2 ;Output to standard error
mov CX,TitleLength ;Length of header string
mov AH,WriteFile ;Output to handle
int DOS ;Call DOS to do it
mov SI,offset env ;Search for 'PATH'
mov es,es:[2ch] ;Get environment segment
call getenv ;Read in PATH string
mov BX,cmdtail ;ES:BX = command parameters
call argc ;Get number of arguments
cmp AX,2 ;At least 1 argument?
jae args_ok ;If yes, keep going
Syntax: mov DX,offset Usage ;DX points to usage string
mov BX,2 ;Output to standard error
mov CX,UsageLength ;Length of usage string
mov AH,WriteFile ;Output to handle
int DOS ;Call DOS to do it
mov AL,0 ;Errorlevel 0 exit
mov AH,ExitWithCode ;AH = Terminate to DOS
int DOS ;Transfer to DOS (for good)
args_ok:
call options ;Scan off any options
; Here, ES:BX = argument address and AX = argument length
cld ;Direction register increments
mov SI,BX ;Point SI to argument
lea DI,cmd1 ;DI = destination
mov CX,AX ;Put character count in CX
mov cmd1_cnt,AX ;And save it for later!
rep movsb ;Move argument to buffer
; End the filename (or PATH if -F used) with a zip.
mov byte ptr [DI],0
; Here, we check for a -F option. If it is true, we tack on the
; default filename (*.MO?) and start a mail run.
cmp F_Flag,true ;Is this a mail run?
jne NotAMailRun ;Nope, continue
cmp byte ptr [DI-1],'\' ;Did they have backslash?
je AddName ;If yes, do the name
mov byte ptr [DI],'\' ;Else add a slash
inc word ptr cmd1_cnt ;And bump counter
inc DI ;Adjust pointer
AddName:
mov byte ptr [DI-1],0 ;Make it ASCIIZ
mov DX,offset cmd1 ;Point to filename/path
mov AX,4300h ;Get attribute
int DOS ;Call DOS to do it
mov byte ptr [DI-1],'\' ;Restore back slash
and CX,00010000b ;Is this a directory?
jnz DirectoryFound ;Go if yes.
mov DX,offset err25 ;Invalid directory message
mov AH,OutputString ;DOS print string function
int DOS ;Call DOS to do it
jmp syntax ;Display syntax screen
DirectoryFound:
mov SI,offset DefaultBundle ;Point to bundle name
mov CX,3 ;Count for name length
rep movsw ;Stuff name in buffer
add cmd1_cnt,6 ;Fix the counter
jmp short Isolate ;No need to check it now
; Here, we will check to make sure there is a valid extension.
; If none was given, a default extention of '.*' will be added.
NotAMailRun:
std ;Set up to move backwards
mov SI,offset cmd1 ;Get address of filename
mov DI,SI ;So we can check for end
mov AX,cmd1_cnt ;Get length in AX
add SI,AX ;Point to end of filename
push SI ;Save end address
scan: lodsb ;Get a character
cmp AL,'.' ;Is it a period?
je ExtentionIsOk ;If yes, extention OK
cmp AL,'\' ;Is it filename separater?
je UseDefault ;Stop if yes
cmp DI,SI ;Scanned whole name?
jne scan ;No, go get more
UseDefault:
pop DI ;DI = end address of filename
mov byte ptr [DI],'*' ;Add full wildcard search
mov byte ptr [DI+1],'.' ;Add a dot to filename
mov byte ptr [DI+2],'*' ;Add wildcard extension
mov byte ptr [DI+3],0 ;End it with a zip
add word ptr cmd1_cnt,3 ;Adjust length count
push DI ;Maintain stack balance
; Next, we isolate the path from the filename so that successive
; filenames can be tacked onto it in case wildcards are used...
public ExtentionIsOk
ExtentionIsOk:
add SP,2 ;Remove garbage from stack
Isolate:
call show_opt ;Display option info
std ;Set up to move backwards
mov SI,offset cmd1 ;Get address of filename
;so we can check for a path.jjn
mov CX,cmd1_cnt ;Get length in CX .jjn
add SI,CX ;SI = end of filename .jjn
dec SI ; .jjn
public path1
path1: lodsb ;Get a character
cmp AL,'\' ;Filename separator?
je save_path ;Stop if yes
cmp AL,':' ;Drive separator?
je save_path ;Stop if yes
loop path1 ;Decrement and loop .jjn
inc SI
mov endpath,SI ;Save address
mov pathlen,CX ;Save path length (0) .jjn
jmp short _end_p ;Skip double save .jjn
public save_path
save_path:
inc SI ;Adjust past \ character
inc SI ;Need 2 for auto dec...
mov endpath,SI ;Save address of end of path
mov pathlen,CX ;Save path length .jjn
_end_p: ; .jjn
cld ;Set direction forward
;
; Now we call the wildcard expander. This creates a list of filenames that
; match the filespec so we can retrieve them later. If there are more than
; 'NamesFound' matches, it will save them on disk.
;
mov on_disk,0 ;List of files is not on disk
mov Name_count,0 ;No names found yet
mov num_names,0
DoAllMail:
call FindNames ; Find all matching files .jjn
cmp F_Flag,true ;Are we doing a mail run?
jne NotDoingMail ;Go if not
mov SI,BundlePosition ;Get address for bundle name
cmp SI,offset SPAZ ;No more names to do?
je NotDoingMail ;If not, we're done...
lodsw ;Get next bundle name
mov DI,EndPath ;End of path to filename
add DI,2 ;Adjust to right spot
stosw ;And stuff in new name
mov BundlePosition,SI ;Save new name offset
jmp short DoAllMail ;And get more filenames
NotDoingMail:
cmp on_disk,0 ;Is stuff on disk?
jz NothingOnDisk ;Nope skip pointer adjust
mov AH,MoveFilePointer ;Move pointer DOS function
xor CX,CX ;Offset from beginning of file
mov DX,CX ;32 bit
mov AL,CL ;Mark for 'beginning'
mov BX,files_handle ;Get the file handle
int DOS ;Call DOS to do it
NothingOnDisk:
mov AX,name_count ; number of names found
or AX,AX ; return with zero flag set
jnz Main ; skip error stuff .jjn
; If we got here, there were no names found.
; (Moved from the old wild_card procedure. .jjn)
cmp F_Flag,true ;Was this a mail run?
jne NormalNotFound ;If not, do normal exit
mov DX,offset NoMail ;Mail run error message
mov AH,OutputString ;DOS print string function
int DOS ;Call DOS to do it
jmp short DoneTotally ;Denis Miller time
NormalNotFound:
mov AX,2 ;Change error to file not found
call err_msg ;Display error in english
push AX ;Save error code
mov SI,offset cmd1 ;Point to filename
call upper ;Convert to upper case
call ShowIt ;Show it (not found)
mov SI,offset crlf ;CR,LF
call ShowIt ;On screen
pop AX ;Restore error code
DoneTotally:
mov AH,ExitWithCode ;Terminate with code
int DOS ;Exit program
; This is the main loop of the program. It is run once for every
; matching filename found from the command line. Needed variables
; are reset each time through.
Main:
mov zooflag,false ;Reset variables
mov byte ptr cmd_cnt,9
mov crushed,false
mov word ptr buf_pos,0
mov flag,false
mov count,false
mov order,false
mov num_hdr,false
mov IsZip,false
mov IsDWC,false
mov IsLZH,false
mov Last_Chance,false
mov DI,offset ExtractOptions ;Point to last set of options
mov CX,9 ;Max options set at 5 bytes
mov AL,blank ;Blank them out (spaces)
rep stosb
mov SI,offset crlf ;Cr,Lf between runs
call ShowIt
call wild_card ;Grab a filename to work on
; If we return from wild_card, at least 1 matching filename was found.
; Otherwise the program reports its status and quits. If a wild card
; was used, it has now been extended to a fully qualified filename. Now
; it has to be checked for archive type etc. etc.
mov SI,offset msg4 ;SI = 'Searching:'
call ShowIt ;Put it on screen
mov SI,offset cmd1 ;SI = filename
call upper ;Convert it to upper case
call ShowIt ;Put it on screen
cmp M_Flag,true ;Displaying net/node?
jne NoAddress ;Skip next part if not
call DisplayNode ;Figure out the info
mov SI,offset info4 ;From message
call ShowIt ;Display it
mov SI,offset BuildNet ;Our ASCII info
call ShowIt ;Display it
NoAddress:
mov SI,offset crlf ;SI = cr/lf
call ShowIt ;On screen
mov SI,offset cmd1 ;SI = full filename
mov DI,offset pakfile ;DI = new command line
do_count:
lodsb ;Get a character from line
cmp AL,0 ;End of filename?
je done ;yes, we are finished
cmp AL,cr
je done1
inc byte ptr cmd_cnt ;Else, bump character counter
stosb ;Save char in command line
jmp short do_count ;and loop back...
done: mov AL,cr ;Cmd line must end with cr
done1: stosb ;Stuff final character
mov byte ptr [DI],0 ;make it ASCIIZ ***
; This little section adds any unique file names that are to be
; extracted from the archive. If this option is used in conjunction
; with /d, the archive will be deleted after extraction. BE CAREFUL
cmp Parsed,true ;Were filenames specified?
jne No_Parsed ;Skip this if not
dec DI ;Back up destination pointer
mov SI,offset Extract_Names ;SI = extract name buffer
mov CX,word ptr Names_Count ;Get length of names
add byte ptr cmd_cnt,CL
rep movsb ;Set up the line
mov byte ptr [DI],cr ;End it all with a cr
mov byte ptr [DI+1],0 ;Make it ASCIIZ
; Here is where we check the archive type. If it is a zoo file, it is
; extracted as is. If it is an ARC/PAK/PK file, it is first checked to
; ensure that it is in proper order by date time...
No_Parsed:
call ArchiveCheck ;Check the archive type
jnc Zoo_Check_OK ;If all is well, continue
jmp main ;Else, try to do the next one
Zoo_Check_OK:
mov DX,offset UnArc4 ;Point to LOOZ.EXE
cmp zooflag,true ;Is this a zoo file?
jne no_zoo
call find ;Does LOOZ exist?
jc no_looz ;Nope, check for zoo
; If execution falls here, LOOZ was found on the path. We have to change
; the extract option to 'x' as looz does not understand 'e'
cmp O_Flag,true ;Do we want forced overwrite?
jne DontForceLooz ;Go if not
jmp short no_looz ;If we do, call zoo instead
DontForceLooz:
mov byte ptr ExtractOptions + 1,'x' ;Change extract option
jmp X_OK ;Go execute looz
; If we get here, a zoo archive was detected, and LOOZ was not found.
; Check for ZOO.EXE and quit if not found...
no_looz:
mov DX,offset UnArc7 ;DX = zoo.exe
cmp O_Flag,true ;Do we want forced overwrite?
jne DoNotForceZoo ;Exit if not, else
mov byte ptr ExtractOptions +2,'S' ;This will force overwrite
mov byte ptr ExtractOptions +3,'O' ;This is needed too
DoNotForceZoo:
mov byte ptr ExtractOptions +1,'x' ;Change extract option
jmp zoo ;Go hunt for it
no_zoo: cmp IsDWC,true ;Is this a DWC file?
jne TryZIP ;Nope, check for ZIP
mov DX,offset UnArc8 ;Point to 'DWC.EXE'
cmp O_Flag,true ;Overwrite mode?
jne DoNotForceDwc ;If not, exit
mov byte ptr ExtractOptions + 1,'x' ;This will allow DWC
mov byte ptr ExtractOptions + 2,'w' ;to overwrite existing files
jmp Zoo ;Try to run it
DoNotForceDwc:
mov byte ptr ExtractOptions + 1,'e' ;Normal extract mode
jmp Zoo ;Try to run it
TryZIP: cmp IsZIP,true ;Is this a ZIP file?
jne TryLZH ;If not, check for LHArc
mov DX,offset UnArc9 ;Point to 'PKUNZIP.EXE'
cmp O_Flag,true ;Overwrite mode?
jne DoNotForceZIP ;Exit if not
mov byte ptr ExtractOptions + 1,'-' ;This will allow Zip
mov byte ptr ExtractOptions + 2,'o' ;to overwrite existing files
jmp Zoo ;Try to run it
DoNotForceZIP:
jmp Zoo ;Try to run it
TryLZH: cmp IsLZH,true ;Is this an LHZ file?
jne TryNormal ;Must be an ARC
mov DX,offset UnArc10 ;Point to 'LHARC.EXE'
mov byte ptr ExtractOptions,'e' ;Must have extract option
cmp O_Flag,true ;Overwrite mode?
jne DoNotForceLZH ;Exit if not
mov byte ptr ExtractOptions + 2,'/' ;This will allow LHArc
mov byte ptr ExtractOptions + 3,'m' ;to overwrite existing files
mov byte ptr ExtractOptions + 4,'c' ;Not very exotic....
jmp Zoo ;Try to run it
DoNotForceLZH:
jmp Zoo ;Try to run it
TryNormal:
call Sort_It
jnc part2 ;Sort was good, go unarc
mov SI,offset sorterr ;Point to error message
call ShowIt ;Put it on screen
Part2:
mov byte ptr ExtractOptions + 1,'e' ;Normal extract option
cmp Crushed,true ;Crushed files?
jne part3 ;Nope, check for ARCE
Part2a: mov DX,offset UnArc5 ;Point to PAK.EXE
cmp O_Flag,true ;Overwrite mode?
jne DoNotForcePak ;Exit if not
mov byte ptr ExtractOptions + 2,' ' ;A space for the new PAK
mov byte ptr ExtractOptions + 3,'/' ;A hyphen for the new PAK
mov byte ptr ExtractOptions + 4,'w' ;This tells pak to force
mov byte ptr ExtractOptions + 5,'a' ; overwrites always
DoNotForcePak:
cmp byte ptr D_flag,true ;Was delete flag set?
jne NoDelete ;Nope, continue...
mov byte ptr ExtractOptions + 1,'x' ;Delete archive when done
NoDelete:
jmp zoo ;Do PAK and PAK only.
part3: cmp byte ptr A_Flag,true ;Default to ARCE?
jne Xarc ;Go if not
NoneFound:
cmp Crushed,true ;Crushed files?
jne OkForArce ;Nope, keep going
jmp Give_Up ;If yes, just quit
OkForArce:
cmp O_Flag,true ;Force overwrite mode?
jne DontForceArce ;Go if not
mov SI,offset pakfile ;Point to command line
goagain:
lodsb
or AL,AL
jnz goagain
mov DI,SI ;Get address in DI
mov byte ptr [DI-2],Blank ;Put in a space
mov byte ptr [DI-1],'/' ;and an Option delimiter
mov byte ptr [DI],'R' ;and Force overwrites...
mov byte ptr [DI+1],cr
mov byte ptr [DI+2],0
add byte ptr cmd_cnt,3 ;Fix the count up
DontForceArce:
mov DX,offset UnArc6 ;Else point to it
mov byte ptr ExtractOptions + 1,' ' ;This removes any options
mov byte ptr ExtractOptions + 2,' ' ; that may have been put
mov byte ptr ExtractOptions + 3,' ' ; in by other un-archers
jmp short zoo ;Go try to run it
Xarc: mov DX,offset UnArc1 ;Point to PKXARC.EXE
mov byte ptr ExtractOptions + 1,' ' ;Remove 'e' option
cmp O_Flag,true ;Overwrite mode?
jne DoNotForceXarc ;Exit if not
mov byte ptr ExtractOptions + 1,'-' ;This forces PKWare to use
mov byte ptr ExtractOptions + 2,'r' ; it's overwrite mode
DoNotForceXarc:
call find ;See if it exists
jnc X_OK ;Got it!
mov DX,offset UnArc2 ;Point to PKXARC.COM
call find ;See if it exists
jnc X_OK ;Got it!
mov DX,offset UnArc3 ;Point to PKUNPAK.EXE
call find ;See if it exists
jnc X_OK ;Got it, keep going
mov DX,offset UnArc5 ;Point to PAK.EXE
mov byte ptr ExtractOptions + 1,'e' ;Set up extract for pak
cmp O_Flag,true ;Overwrite mode?
jne DontForcePak ;Exit if not
mov byte ptr ExtractOptions + 2,' ' ;A space for the new PAK
mov byte ptr ExtractOptions + 3,'/' ;A hyphen for the new PAK
mov byte ptr ExtractOptions + 4,'w' ;This tells pak to force
mov byte ptr ExtractOptions + 5,'a' ;overwrite always
DontForcePak:
cmp byte ptr D_flag,true ;Was delete flag set?
jne part3a ;Nope, continue...
mov byte ptr ExtractOptions + 1,'x' ;Delete archive when done
part3a: call find ;See if it exists
jnc X_OK ;Got it, continue
jmp NoneFound ;Try Arce....
Zoo: call find ;See if it exists
jnc X_OK ;Got it!
; If this code is executed, then no Un-Arc program was found on the
; path. It reports the error and aborts...
Give_Up:
mov AX,22 ;Unarcher not found
call err_msg ;Report error in english
mov AH,ExitWithCode ;Exit with code
int DOS ;Back to DOS (for good)
X_OK: mov BX,offset par_blk ;BX points to spawn info
mov AL,0 ;AL = load and execute
push DS
push ES
cli ;Disable interupts
mov stk_seg,SS ;Save the Stack
mov stk_ptr,SP ;Both parts...
sti ;Enable inerupts
mov AH,ExecuteProgram ;AH = MSDOS exec function
int DOS ;Transfer to DOS
cli ;disable interupts
mov SS,stk_seg ;Restore stack segment
mov SP,stk_ptr ;Restore stack pointer
sti ;Enable interupts
pop ES
pop DS
mov AH,GetReturnCode ;Get return code from Un-Arcer
int DOS ;Transfer to DOS
mov elevel,AL ;Save errorlevel for later
cmp byte ptr crushed,true ;Did we use PAK?
jne normal ;Nope, check for delete flag
cmp byte ptr D_Flag,true ;Did we mark for delete?
jne main_loop ;Exit if no
mov SI,offset del_msg ;SI = 'Unlinking...'
call ShowIt
mov SI,offset cmd1 ;SI = filename
call ShowIt
mov SI,offset crlf
call ShowIt
jmp short main_loop ;Go do next file
normal: or AL,AL ;Make sure all is well
jnz main_loop ;Before allowing a delete
cmp byte ptr D_Flag,true ;Should we delete arc file?
jne main_loop ;Skip if not
mov SI,offset del_msg ;SI = 'Unlinking...'
call ShowIt
mov SI,offset cmd1 ;SI = filename
call ShowIt
mov SI,offset crlf
call ShowIt
mov AH,DeleteFile ;AH = delete file
mov DX,offset cmd1 ;DX = archive name
int DOS ;Call DOS to do it
jnc main_loop ;Go if no errors
call err_msg ;Show errors but continue...
main_loop:
jmp main ;Go get next file
; Print ASCIIZ string pointed to by SI
ShowIt:
mov AH,CharacterOutput ;Function = console out
mov byte ptr Characters,0 ;Set count to zip
show_loop: lodsb ;Get a character
or AL,AL ;Is it a 0?
jz ShowIt_exit ;If yes, exit
inc byte ptr Characters ;Bump char counter
mov DL,AL ;ASCII char in DL
int DOS ;Call DOS to print it
jmp short show_loop ;Go get more
ShowIt_exit:
ret ;Return to caller
Spaz endp
argc proc near ;count command line arguments
push BX ;save original BX and CX
push CX ; for later
mov AX,1 ;force count >= 1
argc1: mov CX,-1 ;set flag = outside argument
argc2: inc BX ;point to next character
cmp byte ptr [BX],cr
je argc3 ;exit if carriage return
cmp byte ptr [BX],blank
je argc1 ;out of argument if blank
cmp byte ptr [BX],tab
je argc1 ;outside argument if ASCII tab
;otherwise not blank or tab,
jcxz argc2 ;jump if already in argument
inc AX ;else found argument, count it
not CX ;set flag = inside argument
jmp argc2 ;and look at next character
argc3: pop CX ;restore original BX and CX
pop BX
ret ;return AX = argument count
argc endp
argv proc near ;get address & length of
;command tail argument
xor AH,AH ;initialize argument countef
argv1: mov CX,-1 ;set flag = outside argument
argv2: inc BX ;point to next character
cmp byte ptr [BX],cr
je argv7 ;exit if carriage return
cmp byte ptr [BX],blank
je argv1 ;outside argument if ASCII blank
cmp byte ptr [BX],tab
je argv1 ;outside argument if ASCII tab
;if not blank or tab...
jcxz argv2 ;jump if already inside argument
inc AH ;else count arguments found
cmp AH,AL ;is this the one we're looking for?
je argv4 ;yes, go find its length
not CX ;no, set flag = inside argument
jmp argv2 ;and look at next character
argv4: ;found desired argument, now
;determine its length...
mov AX,BX ;save param, starting address
argv5: inc BX ;point to next character
cmp byte ptr [BX],cr
je argv6 ;found end if carriage return
cmp byte ptr [BX],blank
je argv6 ;found end if ASCII blank
cmp byte ptr [BX],tab
jne argv5 ;found end if ASCII tab
argv6: xchg BX,AX ;set ES:BX = argument address
sub AX,BX ;and AX = argument length
jmp short argvx ;return to caller
argv7: xor AX,AX ;set AX = 0, argument not found
argvx: ret ;return to caller
argv endp
getenv proc near ; return address and length
; of environment variable
push CX ; save registers
push SI
mov CX,8000h ; assume max env. = 32 KB
xor DI,DI ; initial env. offset
xor AX,AX ; default length result
get1: cmp byte ptr ES:[DI],0 ; check for end of environment
je get4 ; end reached, return AX = 0
pop SI ; initialize address of target
push SI ; variable to be found
repe cmpsb ;Compare target and env. strings
cmp byte ptr [SI-1],0
jne get2 ;Jump if incomplete match
cmp byte ptr ES:[DI-1],'='
je get3 ;Jump if match was complete
get2: repne scasb ;No match, scan for end string
jmp get1 ;Try again to match
get3: push DI ;Save address after = sign
repne scasb ;Look for end of this string
pop AX ;Get back starting address
xchg DI,AX ;Find string length
sub AX,DI
dec AX ;Don't include null byte
get4: pop SI ;Common exit point
pop CX
mov CS:env_len,AX ;Save PATH length
or AX,AX ;Null PATH?
jz get5 ;Exit if yes
push ES ;Get path segment into
pop DS ; DX for string move
push CS ;Now ES points to data
pop ES ; in our code segment
mov CX,AX ;Get length of path in CX
mov SI,DI ;Path is now source
mov DI,offset saved ;Destination is our area
rep movsb ;Move path into this segment
get5: push CS ;Now we have to restore
pop DS ; the original DS
push CS
pop ES
ret ;Return to caller
getenv endp
; This routine searches the current directory, and (if needed), the
; entire PATH, looking for an unarchiver to use. It is called with
; DX pointing to an ASCIIZ filename to look for and returns with
; carry clear if it is found. Carry Set if not found.
find proc near
push DX ;Save pointer to filename
mov AH,SearchForFirst ;Search for first
pop DX ;Get filename address
push DX ;Save it again
xor CX,CX ;Normal attribute
int DOS ;Give it to DOS
jc find1 ;Not found, search path
pop DX ;Point DX to filename
ret ;exit Find...
find1: mov AX,env_len ;Get PATH length
or AX,AX ;Did we find a path?
jnz find2 ;Keep going if yes
no_exist:
pop DX ;Point DX to filename
stc ;Carry set to show error
ret ;Exit Find
find2: mov DI,offset saved ;Point to the path string
mov dir,DI ;dir = start of path string
add DI,AX ;AX = end of path string
mov enddir,DI ;save it
mov byte ptr [DI],0 ;Null terminator for path
find3: mov DI,offset new ;Area for path\filename
mov SI,dir ;Get current address in path
cmp [enddir],SI ;End of path variable?
jbe no_exist ;Not found, exit
find4: lodsb ;Get a character
cmp AL,';' ;Seperator?
je find5 ;Yes, go tack on filename
cmp AL,0 ;Are we finished?
je find5 ;Yes, go
stosb ;Stuff character
jmp short find4 ;and go for another
find5: mov dir,SI ;Save current path address
cmp byte ptr [DI-1],'\' ;Path separator?
je find6 ;Yup, keep goin
mov byte ptr [DI],'\' ;Else, put one in
inc DI ;Bump the pointer
find6: pop SI ;Get filename address
push SI ;Save it back again
find7: lodsb ;Get character from filename
cmp AL,0 ;Got whole filename?
je find8 ;Go if yes
stosb ;Else put character in buffer
jmp find7 ;Go get the rest
find8: stosb ;Save the null (ASCIIZ)
mov AH,SearchForFirst ;Search for first
mov DX,offset new ;Point to path\filename
xor CX,CX ;Normal attribute
int DOS ;Give it to DOS
jc find3 ;Not found try next path
pop DX ;Clear junk off stack
mov DX,offset new ;DX = full path\filename
clc ;Show no errors
ret ;Exit (so we can exec it)
find endp
; This routine determines what type of archive is being worked on.
; It will set a flag to tell SPAZ which un-archiver to try and use.
ArchiveCheck proc near
mov AH,OpenFile ;AH = open file request
mov AL,0 ;read access only
mov DX,offset cmd1 ;Point to archive name
int DOS ;Call DOS to open it
jc probs
xchg AX,BX ;Handle in BX
mov AH,ReadFile ;AH = read file
mov CX,4 ;Read first 4 bytes
mov DX,offset Usage ;Read byte into usage area
int DOS ;Call DOS to do it
jc probs
mov AH,MoveFilePointer ;Get ready to adjust
mov AL,2 ;From end of file
mov CX,0ffffh ;2 spaces
mov DX,0fffeh
int DOS ;Call DOS to do it
jc probs
mov AH,ReadFile ;Read last 2 bytes
mov CX,2
mov DX,offset Usage + 4 ;Buffer for save
int DOS ;Call DOS to do it
jc probs
mov AH,CloseFile ;AH = close file
int DOS ;Call DOS to do it
jc probs
mov AX,word ptr Usage + 4 ;Get DWC bytes
cmp AX,4357h ;Is it a DWC file?
jne IsItZoo ;Go, if not
mov IsDWC,true ;Else set flag
jmp short EndCheck ;And exit
IsItZoo:
mov AX,word ptr Usage ;Get value
cmp AX,4f5ah ;Is it a zoo file?
jne IsItZip ;Go if not, else
mov zooflag,true ;Mark for zoo
jmp short EndCheck
IsItZip:
cmp AX,4b50h ;Is it a ZIP file?
jne IsItArc ;Go, if not
mov IsZip,true ;Set flag
jmp short EndCheck ;We're outa here
IsItArc:
cmp AL,1Ah ;Is it a normal Arc/Pak?
jne IsItLZH ;Skip this file if not
jmp short EndCheck ;We're outa here
IsItLZH:
mov AX,word ptr Usage + 2 ;Get LH's ID bytes
cmp AX,6C2Dh ;Is this an LH Arc?
jne NotAnArchive ;Report error if not
mov IsLZH,true ;Mark for LHArc
EndCheck:
clc ;Show no errors
ret
probs: push AX ;Save error code
call err_msg ;Report error in english
mov SI,offset zerr ;SI = Zoo check error message
call ShowIt ;Display it
pop AX ;Restore error code
NotAnArchive:
stc ;Show error
ret ;Return to caller
ArchiveCheck endp
; This routine is responsible for sorting ARCType bundles into proper
; FidoNet Mail format. i.e. Sorted by date/time. It is accomplished
; by sorting all the headers and re-writting the entire archive...
Sort_It proc near
cld ;Move forward again...
xor AL,AL
mov num_hdr,AL ;Init header counter
mov flag,false
mov DX,offset cmd1 ;DX = Archive filename
mov AH,OpenFile ;AX = Open file
xor AL,AL ;Normal Attribute
int DOS ;Give it to DOS
jnc open_ok ;Continue if it worked
jmp short inv_hdr ;Go report errors
; This routine will read in the archive file headers so that they
; can be sorted.
open_ok:
mov in_handle,AX ;Save file handle
mov buf_pos,0 ;Init buffer position
call read_hdr ;Read in first header
jnc got_1st ;If clear, we're OK
; Truncated file. Somethings weird in Denmark!
mov AX,19 ;Truncated file
inv_hdr:
call err_msg ;Put it on screen
stc
ret ;Exit Sort_It with error
; If we get this far, the first header has been read in. Stuff it in
; the buffer and go for the rest...
got_1st:
mov SI,cmdtail ;Point to arc data
cmp byte ptr [SI+1],0 ;End of Archive?
jne Chk_Crushed ;Exit for sort
jmp got_em
Chk_Crushed:
cmp byte ptr [SI+1],10 ;Crushed file?
jb Not_Crushed ;Nope, continue
mov Crushed,true ;Else, show crushed
Not_Crushed:
cmp byte ptr [SI],1ah ;Do we have a PAK file?
je pak_ok ;If yes, keep going
mov AX,20 ;Invalid header
call err_msg ;Report error in english
add sp,2 ;Remove return address
mov AH,CloseFile ;Close the file
mov BX,in_handle
int DOS ;Call DOS to close file
mov byte ptr elevel,1 ;Report error for no delete
jmp main ;Bad file, try the next one
pak_ok: mov DI,offset hdr_buf ;Get buffer address
add DI,[buf_pos] ;Adjust to current pos
mov AX,low_pos ;Get file pointer low word
mov [DI],AX ;Stuff it in buffer
mov AX,high_pos ;Get file pointer high word
mov [DI+2],AX ;Stuff it in buffer
add DI,4 ;Adjust the pointer
mov CX,29 ;Length of archive header
rep movsb ;Put info in buffer
add buf_pos,arc_len ;Bump the buffer pointer
inc num_hdr
cmp num_hdr,Entries ;Have we got too many?
jb room ;Nope, continue...
mov AX,21 ;Too many archive entries
jmp nope ;Report and exit
room: call read_next ;Get next header
jnc got_1st ;Go stuff it in buffer
jmp short got_em ;Got all headers, exit
read_next:
mov DI,cmdtail ;DI = start of header
mov DX,word ptr [DI+15] ;DX = low byte of arc size
mov CX,word ptr [DI+17] ;CX = high byte of arc size
mov BX,in_handle ;BX = opened file handle
mov AH,MoveFilePointer ;AH = move file pointer
mov AL,1 ;AL = from current position
int DOS ;Give it to DOS
read_hdr:
mov BX,in_handle ;Get opened file handle
xor CX,CX ;Set offset for search
xor DX,DX ; to zero bytes
mov AH,MoveFilePointer ;AH = move file pointrr
mov AL,1 ;AL = from currcnt position
int DOS ;Call DOS to do it
mov high_pos,DX ;Save the high word
mov low_pos,AX ;Save the low word
mov BX,in_handle ;Get opened file handle
mov CX,29 ;Read in 29 bytes
mov DX,cmdtail ;Buffer for read...
mov AH,ReadFile ;Read from file
int DOS ;Give it to DOS
ret
got_em: mov Order,true ;Archive already in order
cmp byte ptr N_Flag,false ;Skip sort?
jne sort ;If yes, exit
mov BX,in_handle ;Get the file handle
mov AH,CloseFile ;So we can close it
int DOS ;Call DOS to do it
jmp Back_to_main ;Exit sort
sort: mov flag,false ;Show no changes made
mov count,1 ;To prevent sort past end
mov AH,num_hdr ;Get number of entrys
cmp AH,1 ;Is there only 1 entry?
jbe sort_exit ;No sort if 0 or 1 entry
mov SI,offset hdr_buf ;SI = start of header buffer
mov DI,offset hdr_buf+arc_len ;DI = 2nd entry in buffer
sort1: mov BX,23 ;BX = offset to header date
mov AX,[SI+BX] ;Get date from 1st entry
mov DX,[DI+BX] ;Got date from 2nd entry
cmp AX,DX ;Which is higher?
ja change ;Swap if 1st > 2nd
jne sort2 ;If not = get next entry
mov BX,25 ; else get offset to time
mov AX,[SI+BX] ;Get time from 1st entry
mov DX,[DI+BX] ;Get time from 2nd entry
cmp AX,DX ;Which is higher?
ja change ;Swap if 1st > 2nd
; If Date and Time are identical, no changes are made
sort2: add SI,arc_len ;Point to next entry
add DI,arc_len ;Point to next entry
inc count ;Bump # of entries completed
mov AH,count ;Get the number
cmp AH,num_hdr ;Done all entries?
je pass ;End of this pass if yes
jmp short sort1 ;Else do next entry
; This section will swap the entry pointed to by SI with the entry
; pointed to by DI...
change: push SI ;Save pointer to 1st entry
push DI ;Save pointer to 2nd entry
mov CX,arc_len ;# of bytes in an entry
chg1: mov AL,[DI] ;Get byte from destination
movsb ;Move Source to Destination
mov [SI-1],AL ;Move Destination to Source
loop chg1 ;Loop back for more
pop DI ;Restore 2nd entry address
pop SI ;Restore 1st entry address
mov flag,true ;A swap has been made (pass)
mov Order,false ;Show swap made (constant)
jmp sort2 ;Do next entry
; Here we check if a change was made. If no changes were made
; then the archive was already in order...
pass: mov AH,flag ;Get the sort flag
cmp AH,true ;Was a change made?
je sort ;Go again if change was made
sort_exit:
mov AL,Order ;Was archive in order?
cmp AL,true ;If yes, do not write
jne write
mov BX,in_handle ;Get the file handle
mov AH,CloseFile ;So we can close it
int DOS ;Call DOS to do it
jmp Back_to_main ;The file out again.
write:
mov DI,offset tempspec ;point to temp filespec .jjn
mov SI,offset cmd1 ;get location of command .jjn
mov CX,pathlen ;get path length .jjn
rep movsb ;make a copy .jjn
mov SI,offset temp ;Point to temp filename .jjn
mov CX,thomlen ;get length of filename .jjn
rep movsb ;copy it after the path .jjn
mov DX,offset tempspec ;Point to temp filespec .jjn
xor CX,CX ;Use normal attribute
mov AH,CreateFile ;AH = create or truncate
int DOS ;Call DOS to do it
jnc create_ok ;Go if all is well
nope: call err_msg ;Report error in english
stc ;Carry = Sort failed
ret ;Back to main section
; Here, the temp file has been created and the handle for that file is
; in AX.
create_ok:
mov out_handle,AX ;Save handle for write file
; Now, we have to read in the sorted entry info, and gather more stuff
; from the archive headers
mov SI,offset hdr_buf ;Point to the sorted info
mov AL,num_hdr ;Get number of entries
nxt_hdr:
mov flag,false ;Use flag for eof check
push AX ;Save # of entries for later
push SI ;Save buffer pointer
mov DX,[SI] ;Get low word of file position
mov CX,[SI+2] ;Get high word of position
mov low_pos,DX
mov high_pos,CX
clc
add DX,29 ;Adjust for arc header
adc CX,0 ;Include carry if any
mov BX,in_handle ;Get read file handle
mov AL,0 ;Offset is from beginning
mov AH,MoveFilePointer ;AH = move file pointer
int DOS ;Call DOS to do it
; The file pointer has been set to the read location. First we
; write the header. Then we read and write the archive data.
hdr_in: call info ;Print the copy info
pop DX ;Get buffer pointer
push DX ;And save it again
add DX,4 ;Skip past file location
mov CX,29 ;Number of bytes to write
mov BX,out_handle ;Get the write file handle
mov AH,WriteFile ;AH = write to file
int DOS ;Call DOS to write the header
jnc hdr_out ;Header written ... go
add sp,4 ;Get rid of stack junk
jmp short nope ;Exit, we had problems
hdr_out:
pop SI ;Point to the header
push SI ;Save it back
mov DX,[SI+21] ;Get high word of entry size
mov AX,[SI+19] ;Get low word of entry size
; DX:AX contains the number of bytes that have to be read/written.
xor CX,CX ;High word of buffer size
mov BX,bsize ;Low word of buffer size
; CX:BX contains the number of bytes we can do at one time.
cont: clc ;Get ready for subtract
sub AX,BX ;Subtract low word
sbb DX,CX ;Subtract high word
push AX
push DX
push BX
push CX
jae more1 ;There's still more to go
clc
add BX,AX ;Add back last result
mov flag,true ;Show end of data reached
; Here BX contains the remaining number of bytes to read write.
; So we have to put it in CX
more1: xchg BX,CX ;Get count in CX
mov DX,offset cpy_buf ;Point to our buffer
mov BX,in_handle ;Handle for read
mov AH,ReadFile ;AH = read file
; Note: CX should contain [bsize] OR the remaining bytes to go...
int DOS ;Call DOS to read file
jnc data_ok ;Got the data
add sp,12 ;Remove stack junk
jmp nope ;Exit, we had probs...
data_ok:
mov BX,out_handle ;Handle for write
mov AH,WriteFile ;AH = write to file
int DOS ;Call DOS to write out buffer
jnc write_ok ;Go if all is well, else
add sp,12 ;Remove junk from stack
jmp nope ;Exit...
write_ok:
cmp flag,true ;Was this end of arc data?
je do_next ;Get next header if yes
pop CX ;Low word buffer size
pop BX ;Low word file size
pop DX ;High word file size
pop AX ;Low word buffer size
jmp cont ;Continue with this entry
do_next:
add SP,8 ;Clear junk off stack
pop SI ;Get back buffer position
add SI,33 ;Adjust to next entry
pop AX ;Get back number of entrys
dec AL ;Subtract 1 from it
jz no_more ;We're done with data
jmp nxt_hdr ;Else go get the next one
no_more:
; Before we quit, we have to write out a 1A 00 to show the end of
; the archive.
mov AH,WriteFile ;AH = write to file
mov BX,out_handle ;Handle for write file
mov CX,2 ;Number of bytes to write
mov DX,offset end_arc ;Point to the data
int DOS ;Call DOS to do it
jnc delete ;We're finished !
jmp nope ;Exit sort routine
; Now that the meat of the work is done, we have to delete the old
; arc file and rename the new one.
delete: mov BX,in_handle
mov AH,CloseFile
int DOS
mov BX,out_handle
mov AH,CloseFile
int DOS
mov DX,offset cmd1 ;Point to original name
mov AH,DeleteFile ;AH = delete file
int DOS ;Call DOS to do it
jnc del_ok
jmp nope
del_ok: mov AH,RenameFile ;AH = rename file
mov DI,offset cmd1 ;Original filename
mov DX,offset tempspec ;Temporary filename .jjn
int DOS ;Call DOS to do it
jnc Back_to_main ;Go if no problems
jmp nope ;Exit program...
Back_to_main:
clc ;Sort done. No errors
ret ;Return to main section
; Convert double word to ascii decimal. Uses divide instruction
; Parameters passed in registers as follows:
; DX:AX = binary word to be converted
DecimalOut:
push DI
push AX
mov DI,offset decbuf ; address of output buffer
mov CX,7 ; buffer length-1
mov AL,' ' ; pad character
rep stosb ; clear buffer & point to end
mov byte ptr [DI], 0 ; init end of string
dec DI
pop AX ;Get low word back
xchg BP,DX ;Save high word
mov BX,10 ;Use base 10 for decimal
mov CL,30h ;For conversion to ASCII
HighWordLoop:
or BP,BP ;Are we done with high words?
jz LowWordLoop ;Yes
xchg AX,BP ;No, get high word
xor DX,DX ;Clear DX
div BX
xchg BP,AX ;Save new high word
div BX ;Divide low word + remainder
or DL,CL ;Convert hex value to ASCII
mov [DI],DL ;Save decimal character
dec DI ;Back up in the buffer
jmp HighWordLoop ;Repeat until done
LowWordLoop:
xor DX,DX ;Clear DX
div BX
or DL,CL ;Convert hex value to ASCII
mov [DI],DL ;Save decimal character
dec DI ;Back up in the buffer
or AX,AX ;Are we done?
jnz LowWordLoop ;No
pop DI
ret
Sort_It endp
;Convert an ASCIIZ string to upper case.
; Call with SI pointing to string to be converted
upper proc near
push SI ; save string address
up1: lodsb ; next character
or AL,AL ; found end (null byte) ?
jz up2 ; yes, jump
cmp AL,'a' ; test if in range 'a'-'z'
jb up1 ; skip it if not >= a
cmp AL,'z'
ja up1 ; skip it if not <= z
sub byte ptr [SI-1],'a'-'A' ; change char to upper case
jmp up1 ; get another char
up2: pop SI ; restore original string
ret ; address and return
upper endp
; This routine is called by the sort. It prints a line of information
; for every entry in the archive detailing its size, filename, and
; new locatio in the archive....
info proc near
mov SI,offset msg1 ;SI = 'Adjusting'
call ShowIt ;Put it on screen
mov BP,SP ;Get stack pointer
mov SI,[BP+2] ;SI = address of arc entry
add SI,6 ;Now SI points to filename
push SI ;Save address for later
call ShowIt ;Put it on screen
mov CX,14 ;Tab length for info screen
sub CL,Characters ;Subtract # of chars printed
mov DL,blank ;AL = space
mov AH,CharacterOutput ;Function = console out
info_loop:
int DOS ;Call DOS to print space
loop info_loop ;Loop till tab is complete
mov SI,offset msg2 ;SI = 'Location ='
call ShowIt ;Put it on screen
mov DX,high_pos ;High word file position
mov AX,low_pos ;Low word file position
call DecimalOut ;Convert to ASCII and print
mov SI,offset decbuf ;Yes, String address to SI
call ShowIt ; Output it
mov SI,offset msg3 ;SI = 'Length ='
call ShowIt ;Put it on screen
pop SI ;Restore Arc filename address
mov AX,[SI+13] ;Low word file size
mov DX,[SI+15] ;High word file size
clc ;Get ready for addition
add AX,29 ;Add in length of header
adc DX,0 ;Add in any carry
call DecimalOut ;Convert to ASCII and print
mov SI,offset decbuf ;Yes, String address to SI
call ShowIt ; Output it
mov SI,offset crlf ;SI = cr/lf
call ShowIt ;Put it on screen
ret ;Return to caller
info endp
; This routine prints one of DOS's error messages and returns to
; which ever section of the code called it...
err_msg proc near
push AX ;Save errorlevel
dec AX ;Adjust for beginning of table
add AX,AX ; * 2 for DW variables
mov SI,AX ;Get offset in SI
mov SI,errmsg[SI] ;Now SI = address of string
call ShowIt ;Put it on screen
pop AX ;Restore errorlevel
ret
err_msg endp
;************************************************************************
; FindNames: find all file names matching the file specification in cmd1.
; REGISTERS ON EXIT:
; AX = number of files found (may be 0).
; ZF = reset if files found, set if no files found.
; This procedure written by Jeffrey J Nonken. (Modified by Dan)
;************************************************************************
public FindNames
FindNames proc near
mov DI,offset save_buf ;Get dest addresm of filename
mov AL,num_names ;Get # of names already there
mov CL,13 ;Length of 1 entry
mul CL ;Names * 13
add DI,AX ;Now DI points into buffer
mov AH,SearchForFirst ;AH = Search for first
xor CX,CX ;Attribute = 'normal'
mov DX,offset cmd1 ;Point to ASCIIZ filename
int DOS ;Give it to DOS
jnc get1fname ; Found a file, process it
jmp no_files ;Finished with search
; Loop to here if buffer was written to disk.
clean_buf:
mov num_names,0 ; no more names in the buffer
mov DI,offset save_buf ;Get dest address of filename
; Loop to here after each file name, look for the next one.
next:
mov AH,SearchForNext ;AH = Search for next
int DOS ;Give it to DOS
jnc get1fname ; Found a file, process it
jmp short NoMoreFiles ; If not, quit now.
get1fname:
;Now we move the filename.ext up to our own ASCIIZ string
;so that open can use the correct path to the file.
mov SI,offset dta_buf+30 ;SI = filename found
mov CX,6 ; Name is <= 13 bytes
; (including trailing null)
rep movsw ; Move 12 bytes (6 words)
movsb ; Move the last byte
inc name_count ; Count up (total count)
inc num_names ; Count up (buffer count)
cmp num_names,NamesFound ; See if we have names yet
jb next ; Just repeat if not
; If we got here, there were at least 'NamesFound' names.
; Start writing them to disk.
cmp on_disk,0 ; See if there's a file open
jnz already_open ; If so, skip the open step
mov DX,offset filename_file ; Get the file's name
mov AH,CreateFile ; Open the file
xor CX,CX ;No attributes
int DOS ; Do it
mov files_handle,AX ; Save the file handle(error)
jnc already_open ; If no errors, write to file
call err_msg ;Report error in english
mov DX,offset TempErr ;Unable to create file
mov AH,OutputString ;DOS print string function
int DOS ;Display error
jmp short NoMoreFiles ;Continue on
; If the temporary file can't be created, we exit here. This will allow
; SPAZ to process at least 'NamesFound' archives before quitting. If this
; is a disk full condition, it will be reported by the un-archiver.
already_open:
mov DX,offset save_buf ; point to buffer
mov BX,files_handle ; get the file handle
mov CX,13 * NamesFound ; number of file names to write
mov AH,WriteFile ; write to the file
int DOS
mov on_disk,1 ; say it's on disk
jmp clean_buf ; loop around and clear buffer
; No more files found. Clean up and exit.
NoMoreFiles: ; Last file was found
cmp on_disk,0 ; see if there is a files file
jz no_files ; if not, just return
cmp num_names,0 ; see if any left in buffer
jz no_files
mov AL,num_names ; Yes, get the number of names
mov BL,13 ; length of a name
mul BL ; how many bytes to write
mov DX,offset save_buf ; point to buffer
mov BX,files_handle ; get the file handle
mov CX,AX ; number of bytes to write
mov AH,WriteFile ; write to the file
int DOS
; Hmmmmm. If disk is full, un-archiver will report error. If it's just
; a bad read/write, DOS's abort, retry, ignore will display. Don't
; think we have to check?
; All files (if any) have been found and buffered or written to disk. Save
; the address of the buffer in case we have files in the buffer. Restore the
; DTA.
no_files:
mov fname_ptr,offset save_buf ;Address of scratch space
mov names_used,0 ; No names used yet
ret
FindNames endp
;****************************************************************************
; wild_card: Each time called this returns the next name in the list, if any.
; It 'returns' it by copying it into the end of the command line buffer
; after the path so it can be used immediatly. If it has no more names,
; it exits the program.
; This procedure written by Jeffrey J. Nonken (and mangled by Dan)
;****************************************************************************
public wild_card
wild_card proc near
mov AX,names_used ; Get number of names returned
cmp AX,name_count ; Compare to total # of names
jb more_names ; If less, we still have some
; We have no names left to return. See if they were on disk. If so, close up.
cmp on_disk,0 ; see if on disk
jz w_skip_close ; if not, skip over the close
mov AH,CloseFile ; close file command
mov BX,files_handle ; get the file handle
int DOS
mov AH,DeleteFile ; Delete file command
mov DX,offset filename_file ; Name of file to delete
int DOS ; Delete our scratch file
w_skip_close:
mov AL,elevel ;Get last reported errorlevel
mov AH,ExitWithCode ;Terminate with return code
int DOS ;Exit program
; We still have names left. Let's see if they're on disk.
more_names:
cmp on_disk,0 ; Are they stored on disk?
jz not_on_disk ; If not, get from the buffer.
; If we got here, the files are stored on disk. Read one name, 13 bytes, right
; into the file spec. The name was originally null terminated, so extra junk
; on the end won't matter.
mov AH,ReadFile ; Read file command
mov BX,files_handle ; get the file handle
mov DX,endpath ;Get end address of path
mov CX,13 ; Read 1 filename
int DOS
jnc w_got1 ; If no carry, we got it
; If we can't process the temp file, SPAZ has no filenames to work with.
; The only safe thing to do, is exit with the errorlevel. This will leave
; any archives intact so they can be handled later.
call err_msg ;Report error in english
mov DX,offset TempErr ;Error processing temp file
mov AH,OutputString ;DOS print string function
int DOS ;Display error
mov AH,ExitWithCode ;Terminate SPAZ
int DOS ;Tell DOS to do it
; If we got here, there are four or fewer filenames, and they are in the
; scratch buffer. fname_ptr points to the current filename. Just copy all
; 13 bytes in; as before, the name was already null terminated.
not_on_disk:
push SI ; Save the index registers
push DI
mov SI,fname_ptr ; get the current source ptr
mov DI,endpath ; Get end address of path
mov CX,6 ; copy 12 bytes (6 words)
rep movsw
movsb ; copy the 13th byte
mov fname_ptr,SI ; save the new pointer
pop DI ; restore the index registers
pop SI
; One way or another, we copied a filename.
w_got1:
inc names_used ; Note that we used a name
clc ; Clear the carry flag
ret
wild_card endp
; The following routine scans each command line option and sets various
; flags according to options used.
options proc near
cld ;Ensure forward movements
xor AX,AX ;Start with argument 1
Opt0: inc AX ;Bump argument number
push AX ;Save argument number
mov BX,cmdtail ;Point BX to command line
call argv ;Get info on argument
or AX,AX ;Did we find an argument?
jnz StillMore
jmp end_Opts ;Nope, we must be done...
StillMore:
push AX ;Save argument length
mov SI,BX ;Address in SI
call upper ;Convert to upper case
lodsb ;Get first character
cmp AL,'/' ;Is this an option?
je Opt1 ;Go get it if yes
cmp AL,'-' ;Option?
jne arc_name ;Get archive name
Opt1: pop AX ;Get argument length back
push AX ;Maintain stack balance
cmp AX,2 ;Check for valid size
jne bad_opt ;Report bad option
lodsb ;Get option ID
cmp AL,'D' ;Delete flag?
jne Opt2 ;Next check if not
mov byte ptr D_Flag,true ;Set flag to delete arc's
jmp short nxt_opt ;Do next option
Opt2: cmp AL,'N' ;Sort flag?
jne Opt3 ;Next check if not
mov byte ptr N_Flag,false ;Set flag for no sort
jmp short nxt_opt ;Do next option
Opt3: cmp AL,'A' ;Default arc program flag?
jne Opt4 ;Next check if not
mov byte ptr A_Flag,true ;Set flag to show default set
jmp short nxt_opt ;Do next option
Opt4: cmp AL,'V' ;Verbose mode desired?
jne Opt5 ;Next check if not
mov byte ptr Q_Flag,false ;**Kludge** inverted quiet
jmp short nxt_opt ;Do next option
Opt5: cmp AL,'F' ;Is this a mail run?
jne Opt6 ;Report bad option if not
mov byte ptr F_Flag,true ;Set up for mail run
jmp short nxt_opt ;Do next option
Opt6: cmp AL,'O' ;Overwrite mode?
jne Opt7 ;Make 1 more check
mov byte ptr O_Flag,true ;Set overwrite mode
jmp short nxt_opt
Opt7: cmp AL,'R' ;For Opus compatibility
jne bad_opt ;Report bad option if not
mov byte ptr O_Flag,true ;Set overwrite mode
jmp short nxt_opt
bad_opt:
call CheckMFlag ;Are we expanding addresses?
jnc Nxt_Opt ;It's Ok, keep going
mov AX,23 ;Unknow option used...
call err_msg ;Report it
jmp syntax ;Show syntax screen and exit
arc_name:
pop AX ;Get length back
push AX ;Maintain stack balance
cmp byte ptr Got_name,true ;Do we have an archive name?
jne arc_name1 ;Nope, go get it
call parse_line ;Yup, pass it the filenames...
jmp short nxt_opt ;Continue with options
arc_name1:
mov Opt_Address,BX ;Save address of file name
mov Opt_Length,AX ;Save length of file name
mov byte ptr Got_name,true ;Set flag to show we got it!
nxt_opt:
pop AX ;Remove argument length
pop AX ;Get arg number to work on
jmp Opt0 ;Continue...
end_Opts:
add SP,2 ;Clean off stack junk
cmp byte ptr Got_name,true ;Did we get a filename?
jne bad_line ;Report error if not
cmp F_Flag,true ;Is this a mail run?
jne RestoreArg ;Go if not
mov byte ptr D_Flag,true ;Set auto delete
mov byte ptr N_Flag,true ;Force an archive sort
mov byte ptr O_Flag,true ;Force overwrite mode
RestoreArg:
mov AX,Opt_Length ;Get length of argument
mov BX,Opt_Address ;Get address of argument
ret ;And we are outa' here..
;If the program falls through to here, all arguments were examined and
;an archive name was NOT found. Report an error, show the syntax screen
;and quit. What else can we do?
bad_line:
mov AX,24
call err_msg
jmp syntax
options endp
CheckMFlag proc near
lodsb ;Get next character
cmp AL,'M' ;Is this the M flag?
jne NotTheMFlag ;Exit if no
call DecimalIn ;Get net number
mov word ptr OurNet,DX ;Save it
call DecimalIn ;Get node number
mov word ptr OurNode,DX ;Save it
mov M_Flag,true ;Set our flag
clc ;Show we processed it
ret ;And exit
NotTheMFlag:
stc ;Oops, a boo-boo...
ret ;Back to caller
CheckMFlag endp
; This routine displays the current settings of the command line
; parameters. i.e. will sort, will not delete etc...
show_opt proc near
push AX
push BX
cmp byte ptr Q_Flag,true ;Quiet mode?
jne NotQuietMode
jmp show_x ;Exit if yes
NotQuietMode:
cld ;Ensure forward movements
mov SI,offset will ;Point to will message
cmp byte ptr A_Flag,true ;Use Arce?
je show1
mov SI,offset wont
show1: call ShowIt
mov SI,offset info1
call ShowIt
mov SI,offset will
cmp byte ptr D_Flag,true ;Delete archives?
je show2
mov SI,offset wont
show2: call ShowIt
mov SI,offset info2
call ShowIt
mov SI,offset will
cmp M_Flag,true ;Expand net address?
je show3
mov SI,offset wont
show3: call ShowIt
mov SI,offset info5
call ShowIt
mov SI,offset will
cmp F_Flag,true ;A mail run?
je show4
mov SI,offset wont
show4: call ShowIt
mov SI,offset info6
call ShowIt
mov SI,offset will
cmp byte ptr O_Flag,true ;Force overwrite mode?
je show5
mov SI,offset wont
show5: call ShowIt
mov SI,offset info7
call ShowIt
mov SI,offset will
cmp byte ptr N_Flag,true ;Sort archive?
je show6
mov SI,offset wont
show6: call ShowIt
mov SI,offset info3
call ShowIt
show_x: pop BX
pop AX
ret
show_opt endp
; This procedure converts an ASCII number to it's binary form. The
; routine will exit when the first non-ascii-number is reached. The
; binary value is returned in DX.
DecimalIn proc near
xor DX,DX ;Initialize variable
DecimalLoop:
lodsb ;Get first character
sub AL,30h ;Subtract ASCII base
jl DecimalExit ;If too low, we're finished
cmp AL,9
jg DecimalExit ;If too high, we're finished
cbw ;Convert to word value
push AX ;Save digit
mov AX,DX
mov CX,10 ;Working with base 10
mul CX ; 10 * digit
mov DX,AX ;Result in DX
pop AX ;Get number back
add DX,AX ;Add number in
jmp short DecimalLoop ;Get next digit
DecimalExit:
ret ;Back to main section
DecimalIn endp
; This routine parses filenames from the command line that must be passed
; to the unarchive program.
parse_line proc near
cld ;Go in the right direction!
mov Parsed,true ;Show names were parsed
mov CX,word ptr Names_Count ;Get current character count
push AX ;Save argument length
add AX,CX ;AX = new length total
mov SI,BX ;Argument address to source
mov DI,offset Extract_Names ;DI = buffer address
add DI,CX ;Adjust to current position
mov byte ptr [DI],blank ;Add in a space
inc DI ;Adjust pointer
inc AX ;Add 1 to total length
mov word ptr Names_Count,AX ;Save new total length
pop CX ;Get argument length in CX
rep movsb ;Move extract name into buffer
mov byte ptr [DI],0 ;End it with a null
ret
parse_line endp
DisplayNode proc near
cmp M_Flag,true ;Should we do this?
jne ExitDisplayNode ;Exit if not
mov SI,endpath ;Point to bundle name
call GetFromAddress ;Decode the Address
mov DI,offset BuildNet ;Where to store it
mov AX,word ptr FromNet ;Get the Senders net
mov DX,word ptr OurNet ;Get our own net
add AX,DX ;Figure out the difference
xor DX,DX ;Get ready for conversion
call DecimalOut ;Convert to ASCII
call InsertAddress ;Add Net number to string
mov AL,'/' ;Address delimiter
stosb ;Stuff it in
mov AX,word ptr FromNode ;Get the Senders node
mov DX,word ptr OurNode ;Get our node address
add AX,DX ;Figure out the difference
xor DX,DX ;Get ready for conversion
call DecimalOut ;Convert to ASCII
call InsertAddress ;Add node number to string
mov byte ptr [DI],0 ;Make it ASCIIZ
ExitDisplayNode:
ret ;Back to main
DisplayNode endp
InsertAddress proc near
mov SI,offset DecBuf ;Point to ASCII buffer
Insert1:
lodsb ;Get a byte
cmp AL,blank ;Is it ASCII space?
je Insert1 ;Loop if yes
Insert2:
stosb ;Not 0, we keep it...
lodsb ;And get another
or AL,AL ;Check for end
jnz Insert2 ;Loop till finished
ret ;Back to caller
InsertAddress endp
GetFromAddress proc near
call GetNet ;Get the net bundle is from
mov word ptr FromNet,DX ;And save it
call GetNet ;Get the node number
mov word ptr FromNode,DX ;And save it
ret ;That's it!
GetNet:
xor DX,DX ;Start with 0
mov CX,4 ;Counter for Hex number
Net1: lodsb ;Grab a byte
sub AL,30h ;Mask off the ASCII
jl Net3 ;Too low, exit
cmp AL,9 ;0 to 9?
jle Net2 ;If yes, no adjustment
and AL,5fh ;Mask off the casing
sub AL,7 ;Adjust for A-F
jl Net3 ;Quit if too low
cmp AL,15 ;Higher than F?
jg Net3 ;Quit if too high
Net2: push CX ;Save character counter
cbw ;Sign extend our number
mov CL,4 ;4 bits per hex character
sal DX,CL ;Shift over previous value
add DX,AX ;And add in the new
pop CX ;Restore character counter
loop Net1 ;Do 4 characters
Net3: ret ;And then exit
GetFromAddress endp
BuildNet equ $ ;Buffer for Net/Node
FromNet equ BuildNet + 12 ;Sending Net
FromNode equ FromNet + 2 ;Sending Node
OurNet equ FromNode + 2 ;Our Net
OurNode equ OurNet + 2 ;Our Node
cpy_buf equ OurNode + 2 ;Storage for copy buffer
hdr_buf equ cpy_buf + bsize ;Buffer to hold headers
cmd1 equ hdr_buf + entries * arc_len ;Buffer for wildcard filenames
new equ cmd1 + 80 ;Buffer for Arc path search
saved equ new + 80 ;Buffer for Arc exec
decbuf equ saved + 192 ;Buffer for decimal conversions
dta_buf equ decbuf + 8 ;Disk Transfer Area
Def_Arc equ dta_buf + 43 ;Default Archive Name
Fcb1 equ Def_Arc + 13 ;File Control Block 1
Fcb2 equ Fcb1 + 37 ;File control Block 2
Cmd_Cnt equ Fcb2 + 37 ;Command Line Char Counter
ExtractOptions equ Cmd_Cnt + 1 ;Options to pass to Un-Archer
Pakfile equ ExtractOptions + 9 ;Filenames to pass to Un-Archer
Extract_Names equ Pakfile + 160 ;Buffer for names to extract
Names_Count equ Extract_Names + 128 ;Count for names to extract
tempspec equ Names_Count + 2 ;Scratch for temp filespec .jjn
save_buf equ tempspec + 80 ; Filename buffer .jjn
stk equ save_buf + (13 * NamesFound) ;Stack Area .jjn
bottom equ stk + 200 ;End of code and data
cseg ends
end entry